package com.sunyuming;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.*;
import org.bouncycastle.cert.jcajce.*;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

import javax.security.auth.x500.X500Principal;
import java.io.*;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Date;

import java.io.FileInputStream;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Random;

public class CertificateGenerator {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static X509Certificate readCertificateFromPem(String filePath) throws Exception {
        try (InputStream is = CertificateGenerator.class.getClassLoader().getResourceAsStream(filePath)) {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(is);
            return certificate;
        }
    }

    public static PrivateKey readPrivateKeyFromPemFile(String filePath) throws Exception {

        ByteArrayOutputStream jarBytes = new ByteArrayOutputStream();
        try (InputStream in = CertificateGenerator.class.getClassLoader().getResourceAsStream(filePath)) {
            int len = -1;
            byte [] bytes = new byte[1024];
            while ((len = in.read(bytes)) != -1) {
                jarBytes.write(bytes, 0, len);
            }
        }

        // 读取PEM文件内容
//        String key = new String(Files.readAllBytes(Paths.get(filePath)));
        String key = new String(jarBytes.toByteArray());
        // 移除PEM头尾标识
        key = key.replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replaceAll("\\s", ""); // 移除所有空白字符

        // Base64解码
        byte[] keyBytes = Base64.getDecoder().decode(key);

        // 使用PKCS#8编码密钥规范创建密钥规范对象
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

        // 获取KeyFactory来生成PrivateKey对象
        KeyFactory kf = KeyFactory.getInstance("RSA"); // 对于RSA密钥
        return kf.generatePrivate(keySpec);
    }

    /**
     * 签发服务证书
     * @param caPrivateKey CA私钥
     * @param caCertificate CA证书
     * @param serverPublicKey 服务端公钥
     * @param subject 证书主题
     * @param serialNumber 序列号
     * @param validityDays 有效期（天）
     * @return 签发的服务证书
     */
    public static X509Certificate generateServerCertificate(
            PrivateKey caPrivateKey,
            X509Certificate caCertificate,
            PublicKey serverPublicKey,
            String subject,
            BigInteger serialNumber,
            int validityDays) throws Exception {

        // 创建证书构建器
        X500Name issuerName = new JcaX509CertificateHolder(caCertificate).getSubject();
        X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(
                issuerName, // 颁发者
                serialNumber,                                                    // 序列号
                new Date(System.currentTimeMillis() - 60000),                            // 生效时间 扰动一分钟
                new Date(System.currentTimeMillis() + validityDays * 24L * 60 * 60 * 1000), // 过期时间
                new X500Name("CN="+subject+", OU=IT, O=MyCompany"),                                           // 主题
                SubjectPublicKeyInfo.getInstance(serverPublicKey.getEncoded())   // 公钥
        );

        // 添加基本约束（非CA证书）
        certificateBuilder.addExtension(
                Extension.basicConstraints,
                true,
                new BasicConstraints(false)
        );

        // 添加密钥用法
        certificateBuilder.addExtension(
                Extension.keyUsage,
                true,
                new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment)
        );

        // 添加扩展密钥用法（TLS Web服务器认证）
        certificateBuilder.addExtension(
                Extension.extendedKeyUsage,
                true,
                new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth)
        );

        // 添加主题密钥标识符
        certificateBuilder.addExtension(
                Extension.subjectKeyIdentifier,
                false,
                createSubjectKeyIdentifier(serverPublicKey)
        );

        // 添加颁发者密钥标识符
        certificateBuilder.addExtension(
                Extension.authorityKeyIdentifier,
                false,
                createAuthorityKeyIdentifier(caCertificate)
        );

        GeneralNames generalNames = new GeneralNames(
                new GeneralName[]{new GeneralName(GeneralName.dNSName, subject),
                        new GeneralName(GeneralName.dNSName, "hhh.com")}
        );
        certificateBuilder.addExtension(
                org.bouncycastle.asn1.x509.Extension.subjectAlternativeName,
                false,
                generalNames
        );

        // 使用CA私钥签名证书
        ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
                .setProvider("BC")
                .build(caPrivateKey);

        // 构建证书
        X509CertificateHolder certificateHolder = certificateBuilder.build(signer);

        // 转换为X509Certificate对象
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        InputStream in = new ByteArrayInputStream(certificateHolder.getEncoded());
        X509Certificate serverCertificate = (X509Certificate) certFactory.generateCertificate(in);
        in.close();

        return serverCertificate;
    }

    /**
     * 创建主题密钥标识符
     */
    private static SubjectKeyIdentifier createSubjectKeyIdentifier(PublicKey publicKey) {
        try {
            SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
            return new JcaX509ExtensionUtils().createSubjectKeyIdentifier(spki);
        } catch (Exception e) {
            throw new RuntimeException("创建主题密钥标识符失败", e);
        }
    }

    /**
     * 创建颁发者密钥标识符
     */
    private static AuthorityKeyIdentifier createAuthorityKeyIdentifier(X509Certificate caCertificate) {
        try {
            SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(
                    caCertificate.getPublicKey().getEncoded());
            return new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(spki);
        } catch (Exception e) {
            throw new RuntimeException("创建颁发者密钥标识符失败", e);
        }
    }

    /**
     * 验证证书链
     */
    public static boolean verifyCertificate(X509Certificate certificate, X509Certificate caCertificate) {
        try {
            certificate.verify(caCertificate.getPublicKey());
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static KeyStore genkeyStore(String host) throws Exception {
        X509Certificate caCertificate = readCertificateFromPem("rootCA.pem");
        PublicKey caPublicKey = caCertificate.getPublicKey();

        PrivateKey caPrivateKey = readPrivateKeyFromPemFile("rootCA-key.pem");

        // 生成服务端密钥对
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        KeyPair serverKeyPair = keyGen.generateKeyPair();

        // 生成随机序列号
        BigInteger serialNumber = new BigInteger(128, new Random());

        // 签发服务证书
        X509Certificate serverCertificate = CertificateGenerator.generateServerCertificate(
                caPrivateKey,
                caCertificate,
                serverKeyPair.getPublic(),
                host,
                serialNumber,
                365
        );

        // 验证证书
//        boolean isValid = CertificateGenerator.verifyCertificate(serverCertificate, caCertificate);
//        System.out.println("证书验证结果: " + isValid);

        // 保存服务证书和私钥到Keystore
        KeyStore serverKeyStore = KeyStore.getInstance("PKCS12");
        serverKeyStore.load(null, null);
//        System.setProperty("javax.net.ssl.trustStore", "rootCA.pem");
        serverKeyStore.setKeyEntry("server", serverKeyPair.getPrivate(), "changeit".toCharArray(),
                new java.security.cert.Certificate[]{serverCertificate, caCertificate});

        return serverKeyStore;
    }

    public static void main(String[] args) throws Exception {
        // 加载CA私钥和证书（假设已存在）
//            KeyStore caKeyStore = KeyStore.getInstance("PKCS12");
//            caKeyStore.load(new FileInputStream("ca.p12"), "password".toCharArray());
//
//            PrivateKey caPrivateKey = (PrivateKey) caKeyStore.getKey("ca", "password".toCharArray());
//            X509Certificate caCertificate = (X509Certificate) caKeyStore.getCertificate("ca");

        KeyStore serverKeyStore = genkeyStore("mymy.com");

        try (FileOutputStream fos = new FileOutputStream("server.p12")) {
            serverKeyStore.store(fos, "changeit".toCharArray());
        }

        System.out.println("服务证书签发完成！");
    }

}